﻿//--------------------------------------------------------------------------
// 
//  Copyright (c) Chili Software.  All rights reserved. 
// 
//  File: MethodHandlerArgs.cs
//
//  Description: Holds utility methods for SQL generation.
// 
//--------------------------------------------------------------------------


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using Chili.Opf3.Storages;
using System.Reflection;

namespace Chili.Opf3.Linq
{
	/// <summary>
	/// This class holds different utility methods that are useful during SQL generation
	/// for classes that implement the <see cref="IMethodHandler">IMethodHandler</see>
	/// interface, such as <see cref="QueryUtilityMethodsHandler">QueryUtilityMethodsHandler</see>
	/// and <see cref="StringMethodsHandler">StringMethodHandler</see>.
	/// </summary>
	public sealed class MethodHandlerArgs
	{
		private LinqQueryCommandBuilder.SqlBuilder _builder;

		/// <summary>
		/// Creates a new instance of the <see cref="MethodHandlerArgs">MethodHandlerArgs Class</see>.
		/// </summary>
		/// <param name="builder">The SqlBuilder associated with the class.</param>
		internal MethodHandlerArgs(LinqQueryCommandBuilder.SqlBuilder builder)
		{
			if (builder == null)
				throw new ArgumentNullException("builder");
			_builder = builder;
		}

		/// <summary>
		/// Adds a parameter to the final SQL command. The string that is returned
		/// is the SQL representation of the parameter that has been added.
		/// </summary>
		/// <param name="value">The value of the parameter.</param>
		/// <param name="valueType">The type of the parameter.</param>
		/// <returns>The string representation of the added parameter.</returns>
		public string AddParameter(object value, Type valueType)
		{
			if (valueType == null)
				throw new ArgumentNullException("valueType");

			return LinqQueryCommandBuilder.AddParameter(value, valueType, _builder, new StringBuilder(), null).ToString();
		}

		/// <summary>
		/// Processes a (sub-)expression and returns the SQL statement for that expression.
		/// </summary>
		/// <param name="expression">The expression that is processed.</param>
		public string ProcessExpression(Expression expression)
		{
			if (expression == null)
				throw new ArgumentNullException("expression");

			return LinqQueryCommandBuilder.ProcessExpression(expression, _builder, new StringBuilder()).ToString();
		}

		/// <summary>
		/// Adds an entity (table) to the final SQL statemetnt.
		/// </summary>
		/// <param name="entity">The entity (table) to add.</param>
		public void AddEntity(string entity)
		{
			if (entity == null)
				throw new ArgumentNullException("entity");

			_builder.AddEntity(entity);
		}

		/// <summary>
		/// Returns the storage on which the final SQL statement is going to run on.
		/// </summary>
		public SqlStorageBase Storage
		{
			get { return _builder.Storage; }
		}

		/// <summary>
		/// Returns the type of the persistent objects that are going to be generated
		/// by the result from the storage. May be an anonymous type, if there is a 
		/// join with an anonymous type as result is involved.
		/// </summary>
		public Type PersistentType
		{
			get { return _builder.PersistentType; }
		}

		/// <summary>
		/// Gets the value of the member expression. Null is returned if no value could
		/// be fetched.
		/// </summary>
		/// <param name="memberExpression">The member expression whose value is returned.</param>
		/// <returns></returns>
		public object GetValue(MemberExpression memberExpression)
		{
			if (memberExpression == null)
				throw new ArgumentNullException("memberExpression");

			// get the instance on where the member is defined.
			object instance = ((ConstantExpression)memberExpression.Expression).Value;

			// check if we have to deal with a property or a field here
			// and get the value.
			PropertyInfo prop = memberExpression.Member as PropertyInfo;
			if (prop != null)
				return prop.GetValue(instance, null);
			FieldInfo field = memberExpression.Member as FieldInfo;
			if (field != null)
				return field.GetValue(instance);

			return null;
		}
	}
}
